home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
IRIX 6.2 Applications 1996 May
/
SGI IRIX 6.2 Applications 1996 May.iso
/
dist
/
impr_dev.idb
/
usr
/
impressario
/
src
/
scan
/
template_driver
/
scan.c.z
/
scan.c
Wrap
C/C++ Source or Header
|
1996-05-06
|
21KB
|
667 lines
/*
* scan.c
*
* Scanner specific module of a scanner driver. This is a
* template for developing a scanner driver for an SGI system;
* add code that communicates with your scanner in the
* appropriate places below, and link with main.o and libscan.a
* to build a scanner driver.
*
* Copyright 1992, Silicon Graphics, Inc.
* All Rights Reserved.
*
* This is UNPUBLISHED PROPRIETARY SOURCE CODE of Silicon Graphics, Inc.;
* the contents of this file may not be disclosed to third parties, copied or
* duplicated in any form, in whole or in part, without the prior written
* permission of Silicon Graphics, Inc.
*
* RESTRICTED RIGHTS LEGEND:
* Use, duplication or disclosure by the Government is subject to restrictions
* as set forth in subdivision (c)(1)(ii) of the Rights in Technical Data
* and Computer Software clause at DFARS 252.227-7013, and/or in similar or
* successor clauses in the FAR, DOD or NASA FAR Supplement. Unpublished -
* rights reserved under the Copyright Laws of the United States.
*/
#ident "$Revision: 1.17 $"
#include <sys/types.h>
#include <sys/prctl.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <dslib.h>
#include <fcntl.h>
#include <invent.h>
#include <scanner.h>
#include <scandrv.h>
#include "scan.h"
#include "main.h"
/*
* struct for the data from a SCSI inquiry command
*/
typedef struct
{
unchar pqt:3; /* peripheral qual type */
unchar pdt:5; /* peripheral device type */
unchar rmb:1, /* removable media bit */
dtq:7; /* device type qualifier */
unchar iso:2, /* ISO version */
ecma:3, /* ECMA version */
ansi:3; /* ANSI version */
unchar aenc:1, /* async event notification supported */
trmiop:1, /* device supports 'terminate io process msg */
res0:2, /* reserved */
respfmt:3; /* SCSI 1, CCS, SCSI 2 inq data format */
unchar ailen; /* additional inquiry length */
unchar res1; /* reserved */
unchar res2; /* reserved */
unchar reladr:1, /* supports relative addressing (linked cmds) */
wide32:1, /* supports 32 bit wide SCSI bus */
wide16:1, /* supports 16 bit wide SCSI bus */
synch:1, /* supports synch mode */
link:1, /* supports linked commands */
res3:1, /* reserved */
cmdq:1, /* supports cmd queuing */
softre:1; /* supports soft reset */
unchar vid[8]; /* vendor ID */
unchar pid[16]; /* product ID */
unchar prl[4]; /* product revision level*/
unchar vendsp[20];/* vendor specific; typically firmware info */
unchar res4[40]; /* reserved for scsi 3, etc. */
/* more vendor specific information may follow */
} INQDATA;
/*
* SCANINFO *
* OpenScanner(char *dev)
*
* Description:
* Get a SCANINFO structure for the scanner connected to dev.
* This opens the device and does an inquiry to find out what
* kind of scanner is attached. If it's one we know about, we
* allocate a SCANINFO structure, fill it in, and return it.
*
* Parameters:
* dev device for the scanner
*
* Returns:
* pointer to a SCANATTRIB if successful, NULL with drverr set if
* error.
*/
/*ARGSUSED*/
SCANINFO *
OpenScanner(char *dev)
{
static SCANINFO scan;
/*
* VERY IMPORTANT NOTE:
*
* If you are writing a driver for a SCSI scanner, and you are
* using libds, make sure that you pass the O_EXCL flag defined in
* /usr/include/fcntl.h to dsopen:
*
* dsreq_t *dsp = dsopen(dev, O_RDONLY | O_EXCL);
*
* If you pass the O_EXCL flag, the open will fail with errno set
* to EBUSY if dev is the /dev/scsi device of a mounted disk;
* otherwise, the open can succeed and you could really screw up
* the disk!
*
* In addition, it is recommended that before issuing any other
* SCSI commands you perform an inquiry command, and verify that
* the device is a scanner by examining the Device Type code of
* the inquiry buffer (this field should be set to 6. You can use
* the INV_SCANNER #define from /usr/include/invent.h). It is
* also recommended that you examine the vendor and product
* identifiers to make sure the device is a scanner of the type
* for which this driver is being written.
*/
/*
* Set the fields of scan to meaningful values as follows:
*
* scan.metric - Use this to indicate whether measurements are
* in inches or centimeters. This applies to all the
* fields of scan that we set that are measurements, and
* when SetupScan is called (see below), this will be the
* unit of measure for the scanning window and the
* scanning resolution.
*
* scan.pagex, scan.pagey, scan.pagewidth, scan.pageheight - the
* size of the scannable area supported by the scanner. Set
* scan.pagex and pagey to the minimum horizontal and vertical
* values for a scanning window (almost always 0 and 0), and
* scan.pagewidth and scan.pageheight to the width and height
* of the scanning area. The right edge of a scanning window
* will not exceed scan.pagex + scan.pagewidth, and the bottom
* edge will not exceed scan.pagey + scan.pageheight.
*
* scan.minxres, scan.maxxres, scan.minyres, scan.maxyres - Set
* these to the minimum and maximum supported resolutions in
* the horizontal and vertical directions.
*
* scan.xres, scan.yres - set these to arrays of floating point
* numbers representing the discrete resolutions supported in
* the horizontal and vertical directions respectively. If
* the scanner we're supports arbitrary resolutions within the
* ranges specified with scan.minxres, scan.maxxres,
* scan.minyres, and scan.maxyres, we don't set these and we
* set scan.nres to 0 (see below).
*
* scan.nres - Set this to the number of elements in scan.xres and
* scan.yres (the arrays must have equal numbers of elements).
* Set scan.nres to 0 to indicate that any resolution is
* supported within the bounds indicated (see above).
*
* scan.types - Set this to point to an array of SCDATATYPE
* structures, one for each of the data types this scanner
* supports. See the Scanner API Specification for type
* conventions for well-behaved scanner drivers.
*
* scan.ntypes - The number of types in the scan.types array.
*
* scan.options - An array of pointers to functions to implement
* scanner specific options. Each function has the format of
* the callback functions in main.c. Command values start at
* SCN_SCANSPECIFIC (#defined in <scanipc.h>. The 0th element
* of scan.types will be called when the command
* (SCN_SCANSPECIFIC + 0) is received by the library, the 1st
* element is called when the command (SCN_SCANSPECIFIC + 1)
* is received, and so on. The interpretation of the SCARGS
* and SCRES parameters should be agreed upon by this module
* and the scanner specific option program that made the call.
*
* scan.noptions - The number of scanner specific options in
* scan.options
*
* scan.priv - This is a private member for use of this module.
* Set it to point to anything you want; this is useful for
* avoiding the use of global variables within this module.
*/
return &scan;
}
/*
* int
* SetupScan(SCANPARAMS *params)
*
* Description:
* Get ready to perform a scan. params is a value result
* parameter; it has fields that describe the scanning parameters
* desired by the scanning application, and fields that this
* function is responsible for setting.
*
* Parameters:
* params scanning parameters (in/out)
*
* Returns:
* 0 if successful, -1 with drverr set if error
*/
/*ARGSUSED*/
int
SetupScan(SCANPARAMS *params)
{
/*
* The input parameters to use to set up the scan are:
* params->s - The SCANINFO struct we returned from OpenScanner
*
* params->xres, params->yres - scanning resolution.
* These will be resolutions that we returned via the
* SCANINFO struct from OpenScanner.
*
* params->x, params->y, params->width, params->height - The
* scanning window. This will be inside the window
* defined by the pagex, pagey, pagewidth, and pageheight
* fields of the SCANINFO struct we returned from OpenScanner.
*
* params->type - The data type to scan. This will be one of
* the types we returned via the SCANINFO struct from
* OpenScanner.
*
* params->preview - 1 if this is a preview, 0 if this is a
* final scan.
*
* params->maxmem - The maximum amount of memory to use for
* each chunk we scan; params->xbytes * params->readlines
* (see output parameters, below) should not exceed this
* value. This is advisory, not enforced; if for some
* reason it is necessary to set readlines such that
* maxmem is exceeded, the main module of the driver will
* honor params->readlines rather than adhering to
* params->maxmem.
*
* Output parameters that we must set before returning 0:
* params->xpixels - The number of pixels in a scan line
*
* params->xbytes - The number of bytes in a scan line
*
* params->ylines - The number of scan lines in the scan
*
* params->readlines - The number of scan lines to read at a
* time. This parameter becomes significant in DoScan(),
* below. In DoScan(), we get buffers from a scan queue
* into which we're supposed to put the scan data; each
* buffer will be big enough to hold params->readlines
* lines of data.
*
* params->convert - Function to convert scan data to
* params->type. The scanner may not directly support the
* four basic types, but we may be able to convert to one
* of them; for example, some scanners return color data
* in a banded format, where the red, blue, and green
* values for each scan line are together. In this case,
* we would set params->convert to SCBandRGB8ToPixelRGB8;
* this is the function in the scan library for doing the
* conversion we want.
*
* If the scanner returns data in precisely the format
* we're returning to the scanning application, no
* conversion is necessary, and we can leave
* params->convert alone (it will have been initialized to
* NULL to indicate that no conversion is necessary).
*
* Other parameters
* scanq, sfreeq - These are the queues for scan buffers, used
* in DoScan below. They are not significant in ScanSetup
* and should be ignored here.
*/
drverr = SCEDEV; /* Generic "device error" error code; see */
/* <scanner.h> for more specific error codes */
return -1;
}
/*
* int
* ScanReset(SCANINFO *scan)
*
* Description:
* Reset the scanner to its ready state. This is called after a
* scan has been aborted.
*
* Parameters:
* scan Describes the scanner to reset
*
* Returns:
* 0 if successful, -1 with drverr set if error
*/
/*ARGSUSED*/
int
ScanReset(SCANINFO *scan)
{
drverr = SCEDEV; /* Generic "device error" error code; see */
/* <scanner.h> for more specific error codes */
return -1;
}
/*
* void
* DoScan(SCANPARAMS *params)
*
* Description:
* Perform a scan. We read the data from the scanner and put it on the
* scan queue so that the image processing process can get it. This
* function exits when it's done; it's called via sproc(2).
*
* Note: calls to SCEnqueue and SCDequeue may not return; that
* is, these functions will call exit if our parent process sets
* certain flags. Be careful that an exit from within SCEnqueue
* or SCDequeue will not strand any memory or leave the address
* space corrupted in any way.
*
* Parameters:
* params parameters for the scan
*/
void
DoScan(SCANPARAMS *params)
{
void *buf;
int toread, curline;
(void)prctl(PR_TERMCHILD);
for (curline = 0; curline < params->ylines;
curline += params->readlines) {
toread = MIN(params->readlines,
params->ylines - curline);
buf = SCDequeue(params->sfreeq); /* SCDequeue might exit! */
/*
* Get the scan data here!
*/
/*
* Chop the buffer up into scan line sized chunks
*/
while (toread--) {
SCEnqueue(params->scanq, buf); /* SCEnqueue might exit! */
buf = (char *)buf + params->xbytes;
}
}
exit(0);
}
/*
* Document feeder functions.
*
* The template versions of these functions are simply stubs that
* inform the application that no document feeder is attached to the
* scanner. If you are writing a driver for a scanner that supports a
* document feeder, these should be implemented appropriately.
*/
/*
* int
* SetFeederFlags(SCANINFO *scan, SCFEEDERFLAGS flags)
*
* Description:
* Set document feeder flags. flags should be set to either
* SC_AUTOFEED or SC_PROGFEED, depending on whether the
* application wants us to load the next document every time we
* do a scan.
*
* This function should only get called if scan->feederFlags have
* both the SC_AUTOFEED and SC_PROGFEED bits set, indicating that
* the application has to choose how it wants the feeder to act.
*
* Parameters:
* scan scanner info
* flags either SC_AUTOFEED or SC_PROGFEED
*
* Returns:
* 0 if successful, -1 if error
*/
/*ARGSUSED*/
int
SetFeederFlags(SCANINFO *scan, SCFEEDERFLAGS flags)
{
drverr = SCENOFEEDER;
return -1;
}
/*
* int
* AdvanceFeeder(SCANINFO *scan)
*
* Description:
* Advance document feeder so that next document in the feeder
* will be scanned from next time DoScan is called. This should
* only be called if we support SC_PROGFEED. If we claimed
* support for both SC_PROGFEED and SC_AUTOFEED, the application
* should have called SetFeederFlags(SC_PROGFEED).
*
* Parameters:
* scan scanner info.
*
* Returns:
* 0 if successful, -1 if error
*/
/*ARGSUSED*/
int
AdvanceFeeder(SCANINFO *scan)
{
drverr = SCENOFEEDER;
return -1;
}
/*
* int
* FeederReady(SCANINFO *scan)
*
* Description:
* Check whether the document feeder is ready; that is, it has
* paper in it and will be used for scanning.
*
* Parameters:
* scan scanner info
*
* Returns:
* 0 if feeder is ready, -1 otherwise.
*/
/*ARGSUSED*/
int
FeederReady(SCANINFO *scan)
{
drverr = SCENOFEEDER;
return -1;
}
/*
* The next two functions are used to implement the "-query" flag that
* each scanner driver must support. scaninst uses this flag to get
* information about scanners on the system and scanner drivers that
* are installed to aid the user in setting up the
* /var/scan/scanners file.
*/
/*
* void
* PrintID(FILE *fp)
*
* Description:
* Print a string to fp that describes the type of scanner that
* this driver supports
*
* Parameters:
* fp stream upon which to print scanner id string
*/
void
PrintID(FILE *fp)
{
(void)fprintf(fp, "Scanner Template\n"); /* String describing scanner */
(void)fprintf(fp, "SCSI Serial Parallel\n");/* Device type; can be list */
}
/*
* void
* FindScanners(FILE *fp)
*
* Description:
* Look for scanners that this driver can support. For each such
* driver, print the type of device, a space, and then the file
* to open to access that scanner (usually a device special
* file).
*
* Type names are:
* SCSI
* Serial
* Parallel
* GPIB
* EISA
* Other
*
* Parameters:
* fp stream upon which to print stuff
*/
void
FindScanners(FILE *fp)
{
inventory_t *inv;
char device[100];
dsreq_t *dsp;
/* int because it must be word aligned. */
int inqbuf[(sizeof(INQDATA) + 3)/sizeof(int)];
INQDATA *inq = (INQDATA *)inqbuf;
/*
* This example looks for SCSI scanners; do whatever is necesary
* to find other types of scanner here.
*/
if (setinvent() < 0) {
return;
}
while ((inv = getinvent()) != NULL) {
if (inv->inv_class == INV_SCSI && inv->inv_type == INV_SCANNER) {
(void)sprintf(device, "/dev/scsi/sc%dd%dl0", inv->inv_controller,
inv->inv_unit);
if ((dsp = dsopen(device, O_RDONLY)) == NULL) {
continue;
}
if (inquiry12(dsp, (char *)inq, sizeof *inq, 0) == 0
&& strncmp((char *)inq->vid, "vendorXX", 8) == 0 &&
strncmp((char *)inq->pid, "productXXXXXXXXX", 16) == 0) {
(void)fprintf(fp, "SCSI %s\n", device);
}
dsclose(dsp);
}
}
endinvent();
}
/*
* int
* InstallScanner(char *dev)
*
* Description:
* This function gets called to implement the "-install" option
* of the driver. The scanner installation tool wants to install
* a scanner with us as the driver and dev as the device.
*
* This function should verify that this is a reasonable thing to
* do, and should also take steps to ensure that all users can
* access the scanner. This means that for SCSI scanners that
* use the /dev/scsi interface, the following code should be
* executed:
*
* chmod(dev, 0666);
*
* Suggestion: put the code that verfies that a device is valid
* in the OpenScanner function, and then call OpenScanner from
* within this function (InstallScanner). If OpenScanner returns
* NULL, print an error message and return -1.
*
* If for any reason a scanner with us as the driver and dev as
* the device should NOT be installed, print an error message to
* stdout, and return -1. If it's OK to install the scanner,
* return 0.
*
* If we print something and return -1, then scaninst will
* display the string.
*
* Parameters:
* dev Device to use to install scanner
*
* Returns:
* 0 if successful, -1 if error.
*/
int
InstallScanner(char *dev)
{
(void)printf("The template driver doesn't support %s\n", dev);
return -1;
}
/*
* int
* DeleteScanner(char *dev)
*
* Description:
* This function gives the scanner driver the opportunity to
* deallocate any resources allocated during InstallScanner, and
* to do any scanner-specific cleanup necessary for deleting a
* scanner.
*
* If an error occurs, print a message to stdout and return -1.
* scaninst will display the message that gets printed and refuse
* to delete the scanner.
*
* Parameters:
* dev Device of scanner being deleted
*
* Returns:
* 0 if successful, -1 if error.
*/
/*ARGSUSED*/
int
DeleteScanner(char *dev)
{
return 0;
}
/*
* void *
* GetSaveOptions(SCANINFO *scan, int *nBytes)
*
* Description:
* This function should return to the main.c module a pointer to
* some bytes representing our current settings that we got from
* our scanner specific options program. If we don't have a
* scanner specific options program, we just set drverr and
* return NULL.
*
* The reason for doing this is so that the scanner application
* can save some state for us, and at a later time give us the
* same bytes back so that we can make our state match what it
* was before.
*
* Parameters:
* scan SCANINFO
* nBytes we fill this in with the number of bytes we're returning
*
* Returns:
* pointer to bytes containing scanner specific options settings
* if successful, NULL if error. drverr must be set to an
* appropriate error code from <scanner.h> or <sys/errno.h> if an
* error occurs.
*/
void *
GetSaveOptions(SCANINFO *scan, int *nBytes)
{
drverr = SCENOSAVEOPT;
return NULL;
}
/*
* int
* SetSaveOptions(SCANINFO *scan, void *options, int nBytes)
*
* Description:
* In this function, the scanner application is restoring state
* that it previously saved after calling GetSaveOptions. We
* should reset our state to reflect the options passed to us.
*
* These are scanner specific settings that were set by our
* scanner specific options program; we don't need to worry about
* things like resolution and scanning area and data type that
* are a part of the standard scanning protocol here.
*
* Parameters:
* scan SCANINFO
* options the saved settings
* nBytes number of bytes pointed to by options
*
* Returns:
* 0 if successful, -1 if error. drverr must be set to an
* appropriate error code from <scanner.h> or <sys/errno.h> if an
* error occurs.
*/
int
SetSaveOptions(SCANINFO *scan, void *options, int nBytes)
{
drverr = SCENOSAVEOPT;
return -1;
}